package com.foreveredu.propms.service.impl;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Transactional;

import com.foreveredu.propms.domain.Account;
import com.foreveredu.propms.domain.Bill;
import com.foreveredu.propms.domain.BillOther;
import com.foreveredu.propms.domain.ChargeCriterion;
import com.foreveredu.propms.domain.ChargeItem;
import com.foreveredu.propms.domain.ChargeRecord;
import com.foreveredu.propms.domain.Exchange;
import com.foreveredu.propms.domain.House;
import com.foreveredu.propms.domain.Owner;
import com.foreveredu.propms.domain.SubAccount;
import com.foreveredu.propms.domain.SubDistrict;
import com.foreveredu.propms.domain.Utilities;
import com.foreveredu.propms.persist.IAccountDao;
import com.foreveredu.propms.persist.IBillDao;
import com.foreveredu.propms.persist.IBillOtherDao;
import com.foreveredu.propms.persist.IChargeCriterionDao;
import com.foreveredu.propms.persist.IChargeRecordDao;
import com.foreveredu.propms.persist.IExchangeDao;
import com.foreveredu.propms.persist.IHouseDao;
import com.foreveredu.propms.persist.ISinglePropertyChargeCriterionDao;
import com.foreveredu.propms.persist.ISubAccountDao;
import com.foreveredu.propms.persist.IUtilitiesDao;
import com.foreveredu.propms.service.IBusinessService;

@Transactional
public class BusinessService implements IBusinessService {

	private IChargeRecordDao chargeRecordDao = null;
	private IHouseDao houseDao = null;
	private IChargeCriterionDao chargeCriterionDao = null;
	private IUtilitiesDao utilitiesDao = null;
	private IBillDao billDao = null;
	private IBillOtherDao billOtherDao = null;
	private ISinglePropertyChargeCriterionDao spChargeCriterionDao = null;
	private IAccountDao accountDao = null;
	private IExchangeDao exchangeDao = null;
	private ISubAccountDao subAccountDao = null;

	//获得日志记录器
	private Logger log = Logger.getLogger(BusinessService.class);
	
	
	public IBillOtherDao getBillOtherDao() {
		return billOtherDao;
	}

	public void setBillOtherDao(IBillOtherDao billOtherDao) {
		this.billOtherDao = billOtherDao;
	}
	
	public IChargeRecordDao getChargeRecordDao() {
		return chargeRecordDao;
	}

	public void setChargeRecordDao(IChargeRecordDao chargeRecordDao) {
		this.chargeRecordDao = chargeRecordDao;
	}

	public IHouseDao getHouseDao() {
		return houseDao;
	}

	public void setHouseDao(IHouseDao houseDao) {
		this.houseDao = houseDao;
	}

	public IChargeCriterionDao getChargeCriterionDao() {
		return chargeCriterionDao;
	}

	public void setChargeCriterionDao(IChargeCriterionDao chargeCriterionDao) {
		this.chargeCriterionDao = chargeCriterionDao;
	}

	public IUtilitiesDao getUtilitiesDao() {
		return utilitiesDao;
	}

	public void setUtilitiesDao(IUtilitiesDao utilitiesDao) {
		this.utilitiesDao = utilitiesDao;
	}

	public IBillDao getBillDao() {
		return billDao;
	}

	public void setBillDao(IBillDao billDao) {
		this.billDao = billDao;
	}

	public ISinglePropertyChargeCriterionDao getSpChargeCriterionDao() {
		return spChargeCriterionDao;
	}

	public void setSpChargeCriterionDao(ISinglePropertyChargeCriterionDao spChargeCriterionDao) {
		this.spChargeCriterionDao = spChargeCriterionDao;
	}

	public IAccountDao getAccountDao() {
		return accountDao;
	}

	public void setAccountDao(IAccountDao accountDao) {
		this.accountDao = accountDao;
	}

	public IExchangeDao getExchangeDao() {
		return exchangeDao;
	}

	public void setExchangeDao(IExchangeDao exchangeDao) {
		this.exchangeDao = exchangeDao;
	}
	
	public ISubAccountDao getSubAccountDao() {
		return subAccountDao;
	}

	public void setSubAccountDao(ISubAccountDao subAccountDao) {
		this.subAccountDao = subAccountDao;
	}

	@Override
	public void countChargeRecordForHouseAndDate(House house, int year,
			int month) {

	}

	@Override
	public List<ChargeRecord> findChargeRecordByHouseAndDate(House house,
			int year, int month) {
		return chargeRecordDao.findChargeRecordByHouseAndDate(house, year,
				month);
	}

	//查询某账单所包含的收费记录列表
	@Override
	public List<ChargeRecord> findChargeRecordsByBill(Bill bill) {
		return chargeRecordDao.findByBill(bill);
	}
	
	@Override
	public void calAllHousesChargeRecord(int year, int month) {

	}

	/*
	 * Utilities水电数据记录对象的业务处理
	 */

	@Override
	public void deleteUtilitiesById(int id) {
		Utilities u = utilitiesDao.findById(id);
		utilitiesDao.delete(u);
	}

	@Override
	public Utilities findUtilitiesByHouseAndDate(House house, int year,
			int month) {
		return utilitiesDao.findByHouseAndDate(house, year, month);
	}

	@Override
	public Utilities findUtilitiesById(int id) {
		return utilitiesDao.findById(id);
	}

	@Override
	public List<Utilities> findUtilitiess() {
		return utilitiesDao.findAll();
	}

	@Override
	public void saveUtilities(Utilities utilities) {
		utilitiesDao.save(utilities);
	}

	@Override
	public void updateUtilities(Utilities utilities) {
		utilitiesDao.update(utilities);
	}

	/*
	 * Bill账单记录对象的业务处理
	 */
	//为小区中所有房产创建每月账单
	//为避免系统自动计费重复生成账单，可在再次进行系统自动计费时删除之前产生的本月账单。
	@Override
	public void createBillForHouseOfSubDistrict(SubDistrict subDistrict,
			int year, int month) throws Exception {
		//获得小区中的所有房产
		List<House> houseList = houseDao.findBySubDistrict(subDistrict);
		
		//如果重复计费，则删除之前为小区中每个房产自动生成的本月账单
		for(House house:houseList) {
			Bill bill = billDao.findByHouseAndMonth(house, year, month);
			if (bill==null) {
				continue;
			} else {
				billDao.delete(bill);
			}
		}
		
		//为每个房产生成本月账单
		for(House house:houseList) {
			Bill bill = new Bill();
			bill.setHouse(house);
			
			//此账单所对应的收费记录集合
			Set<ChargeRecord> records = new HashSet<ChargeRecord>();
			double totalMoney = 0;
			
			//获得该房产的所有收费项目
			List<ChargeItem> itemList = new ArrayList<ChargeItem>();
			itemList.addAll(house.getChargeItems());
			
			//为该房产的每个收费项目按照相应收费标准创建收费记录
			for(ChargeItem item : itemList) {
				//判断收费项目的收费方式
				if(item.getChargeWay().getId()==1) {
					//按月收费
					ChargeRecord cr = new ChargeRecord();
					cr.setChargeItem(item);
					
					//查找该房产应缴纳的收费项目所对应的物业收费标准
					ChargeCriterion cc = null; 
					
					//判断此收费项目所对应的是否为单独收费标准
					if (item.getItemId().equals("2")||item.getItemId().equals("12")||item.getItemId().equals("13")||item.getItemId().equals("14")||item.getItemId().equals("15")||item.getItemId().equals("16")) {
						cc = chargeCriterionDao.findCriterionByHouseAndItem(house,item,subDistrict);
					} else {
						cc = chargeCriterionDao.findCriterionByTypeAndItem(house.getType(),	house.getBuilding().getType(), house.getSource(), item, subDistrict);
					}
					cr.setChargeCriterion(cc);
					
					//日志记录未设置收费标准的房产信息
					if (cc== null) {
						log.info("未设置收费标准房产编号:"+house.getHouseId());
					}
					
					double money = 0;
					//根据当前的收费项目和收费标准计算费用
					if(item.getItemId().equals("1")) {
						//物业管理费
						money = Double.parseDouble(new DecimalFormat("0.00").format(house.getArea()*cc.getAmount()));
					} else if(item.getItemId().equals("3")||item.getItemId().equals("12")) {
						//电费或单独电费
						Utilities util = utilitiesDao.findByHouseAndDate(house, year, month);
						money = (util==null)?0:Double.parseDouble(new DecimalFormat("0.00").format(((util.getPowerEnd()-util.getPowerBegin())+(util.getPower2End()-util.getPower2Begin()))*cc.getAmount()));
					} else if(item.getItemId().equals("4")||item.getItemId().equals("13")) {
						//水费或单独水费
						Utilities util = utilitiesDao.findByHouseAndDate(house, year, month);
						money = (util==null)?0:Double.parseDouble(new DecimalFormat("0.00").format(((util.getWaterEnd()-util.getWaterBegin())+(util.getWater2End()-util.getWater2Begin()))*cc.getAmount()));
					} else if (item.getItemId().equals("8")||item.getItemId().equals("16")) {
						//二次提水电费或单独二次提水电费
						Utilities util = utilitiesDao.findByHouseAndDate(house, year, month);
						money = (util==null)?0:Double.parseDouble(new DecimalFormat("0.00").format(((util.getWaterEnd()-util.getWaterBegin())+(util.getWater2End()-util.getWater2Begin()))*cc.getAmount()));
					} else {
						//停车费或垃圾清运费或路灯电费或单独物业服务费
						money = Double.parseDouble(new DecimalFormat("0.00").format(cc.getAmount()));
					}
					cr.setWantMoney(money);
					
					//统计所有收费项目的总金额
					totalMoney += money;
					
					//设置cr收费记录对象所属账单
					cr.setBill(bill);
					
					//将当前收费记录添加到Set集合中
					records.add(cr);
					
					//保存当前cr收费记录对象
					chargeRecordDao.save(cr);
				} else if (item.getChargeWay().getId()==2) {
					//按半年收费
					//查看该收费项目当前年度是否已两次收费
					List<ChargeRecord> crList = chargeRecordDao.findByHouseAndChargeItemInYear(house, item, year);
					//如果未收费或当前年度只收取一次费用，则收取半年费用
					if(crList == null || crList.size()<2) {
						ChargeRecord cr = new ChargeRecord();
						cr.setChargeItem(item);
						
						//查找该房产应缴纳的收费项目所对应的物业收费标准
						ChargeCriterion cc = chargeCriterionDao.findCriterionByTypeAndItem(house.getType(),	house.getBuilding().getType(), house.getSource(), item);
						cr.setChargeCriterion(cc);
						
						double money = cc.getAmount();
						
						cr.setWantMoney(money);
						
						//统计所有收费项目的总金额
						totalMoney += money;
						
						//设置cr收费记录对象所属账单
						cr.setBill(bill);
						
						//将当前收费记录添加到Set集合中
						records.add(cr);
						
						//保存当前cr收费记录对象
						chargeRecordDao.save(cr);
					}
				} else if (item.getChargeWay().getId()==3) {
					//按年收费
					//查看该收费项目当前年度是否已收费
					List<ChargeRecord> crList = chargeRecordDao.findByHouseAndChargeItemInYear(house, item, year);
					//如果未收费，则收取该年度费用
					if(crList == null) {
						ChargeRecord cr = new ChargeRecord();
						cr.setChargeItem(item);
						
						//查找该房产应缴纳的收费项目所对应的物业收费标准
						ChargeCriterion cc = chargeCriterionDao.findCriterionByTypeAndItem(house.getType(),	house.getBuilding().getType(), house.getSource(), item);
						cr.setChargeCriterion(cc);
						
						double money = cc.getAmount();
						
						cr.setWantMoney(money);
						
						//统计所有收费项目的总金额
						totalMoney += money;
						
						//设置cr收费记录对象所属账单
						cr.setBill(bill);
						
						//将当前收费记录添加到Set集合中
						records.add(cr);
						
						//保存当前cr收费记录对象
						chargeRecordDao.save(cr);
					}
				} else if (item.getChargeWay().getId()==4) {
					//一次性收费
					//查看该收费项目是否已经收费，
					ChargeRecord cr = chargeRecordDao.findByHouseAndChargeItem(house, item);
					//如果未收费，则一次性收取该费用
					if(cr == null) {
						cr = new ChargeRecord();
						cr.setChargeItem(item);
						
						//查找该房产应缴纳的收费项目所对应的物业收费标准
						ChargeCriterion cc = chargeCriterionDao.findCriterionByTypeAndItem(house.getType(),	house.getBuilding().getType(), house.getSource(), item);
						cr.setChargeCriterion(cc);
						
						double money = cc.getAmount();
						
						cr.setWantMoney(money);
						
						//统计所有收费项目的总金额
						totalMoney += money;
						
						//设置cr收费记录对象所属账单
						cr.setBill(bill);
						
						//将当前收费记录添加到Set集合中
						records.add(cr);
						
						//保存当前cr收费记录对象
						chargeRecordDao.save(cr);
					}
				}
			 }
			
			bill.setAmount(Float.parseFloat(new DecimalFormat("0.0").format(totalMoney)));
			bill.setRecords(records);
			bill.setYear(year);
			bill.setMonth(month);
			bill.setIsPaid(0);//设置账单为"未付款"状态
			bill.setIsInvoiced(0);//设置账单为"未开票"状态
			
			//创建该房产的每月账单
			billDao.save(bill);
		}

	}

	//查找某房产某月份的账单
	public Bill findBillByHouseAndMonth(House house, int year, int month) {
		return billDao.findByHouseAndMonth(house, year, month);
	}
	
	
	@Override
	public void deleteBillById(int id) {
		Bill bill = billDao.findById(id);
		billDao.delete(bill);
	}

	@Override
	public Bill findBillById(int id) {
		return billDao.findById(id);
	}

	@Override
	public List<Bill> findBills() {
		return billDao.findAll();
	}

	@Override
	public void saveBill(Bill bill) {
		billDao.save(bill);
	}

	@Override
	public void updateBill(Bill bill) {
		billDao.update(bill);
	}

	@Override
	public void deleteUtilitiesByHouseAndDate(House house, int chargeYear, int chargeMonth) {
		Utilities u = utilitiesDao.findByHouseAndDate(house, chargeYear, chargeMonth);
		if (u != null) {
			utilitiesDao.delete(u);
		}
	}

	/*
	 * Account账单对象的业务逻辑处理
	 */	
	public void saveAccount(Account account) {
		accountDao.save(account);
	}

	public void deleteAccountById(int id) {
		Account account = accountDao.findById(id);
		accountDao.delete(account);
	}

	public void updateAccount(Account account) {
		accountDao.update(account);
	}

	public List<Account> findAccounts() {
		return accountDao.findAll();
	}

	public Account findAccountById(int id) {
		return accountDao.findById(id);
	}

	/*
	 * Exchange账单对象的业务逻辑处理
	 */	
	public void saveExchange(Exchange exchange) {
		exchangeDao.save(exchange);
	}

	public void deleteExchangeById(int id) {
		Exchange exchange = exchangeDao.findById(id);
		exchangeDao.delete(exchange);
	}

	public void updateExchange(Exchange exchange) {
		exchangeDao.update(exchange);
	}

	public List<Exchange> findExchanges() {
		return exchangeDao.findAll();
	}

	public Exchange findExchangeById(int id) {
		return exchangeDao.findById(id);
	}

	@Override
	public Account findAccountByOwner(Owner owner) {
		return accountDao.findByOwner(owner);
	}

	@Override
	public float findHistoryDebtOfHouse(House house) {
		return billDao.findHistoryDebtOfHouse(house);
	}

	@Override
	public Bill findHistoryBillOfHouse(House house) {
		return billDao.findHistoryBillOfHouse(house);
	}

	@Override
	public float findHistoryDebtOfOwner(Owner owner) {
		float totalDebt = 0;
		Set<House> houses = owner.getHouses();
		for(House house : houses) {
			totalDebt += billDao.findHistoryDebtOfHouse(house);
		}
		return totalDebt;
	}

	@Override
	public List<Bill> findNotPaidBillsOfHouse(House house) {
		return billDao.findNotPaidBillsOfHouse(house);
	}

	@Override
	public void deleteSubAccountById(int id) {
		SubAccount subAccount = subAccountDao.findById(id);
		subAccountDao.delete(subAccount);
	}

	@Override
	public SubAccount findSubAccountById(int id) {
		return subAccountDao.findById(id);
	}

	@Override
	public List<SubAccount> findSubAccounts() {
		return subAccountDao.findAll();
	}

	@Override
	public void saveSubAccount(SubAccount subAccount) {
		subAccountDao.save(subAccount);
	}

	@Override
	public void updateSubAccount(SubAccount subAccount) {
		subAccountDao.update(subAccount);
	}

	@Override
	public SubAccount findSubAccountByType(Account account, int type) {
		return subAccountDao.findByType(account, type);
	}

	@Override
	public List<BillOther> findBillOthers() {
		return billOtherDao.findAll();
	}

	@Override
	public BillOther findBillOtherById(int id) {
		return billOtherDao.findById(id);
	}

	@Override
	public List<Bill> findBillsByBillOther(BillOther billOther) {
		return billDao.findBillsByBillOther(billOther);
	}

	@Override
	public List<Bill> findBillsOfHouse(House house) {
		return billDao.findBillsOfHouse(house);
	}
	
}
